package main

import (
	"fmt"
	"math"
)

type Vertex struct {
	X, Y float64
}

func main() {
	Pointer()  // 指针类型需要指针
	TypeIndi() //值类型需要值类型
}

//============================================================================

// 带指针参数的函数必须接受一个指针
// 接收者为指针的的方法被调用时，接收者既能是值又能是指针
func Pointer() {
	v := Vertex{3, 4}
	p := &Vertex{4, 3} //结构体指针

	//ScaleFunc(v,10) <= 错误
	ScaleFunc(&v, 10)
	ScaleFunc(p, 8)

	//语句 v.Scale(5) 来说，即便 v 是一个值而非指针，带指针接收者的方法也能被直接调用
	//由于 Scale 方法有一个指针接收者，为方便起见，Go 会将语句 v.Scale(5) 解释为 (&v).Scale(5)
	v.Scale(2)
	p.Scale(3)
}

func (v *Vertex) Scale(f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}

func ScaleFunc(v *Vertex, f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}

//==================================================================

// 接受一个值作为参数的函数必须接受一个指定类型的值
// 以值为接收者的方法被调用时，接收者既能为值又能为指针;
// 调用方法 p.Abs() 会被解释为 (*p).Abs()
func TypeIndi() {
	v := Vertex{3, 4}
	// fmt.Println(AbsFunc(&v))  <= 错误
	fmt.Println(AbsFunc(v))

	fmt.Println(v.Abs()) // 正确
	p := &v              //指针结构体
	fmt.Println(p.Abs()) //正确
}

func (v Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func AbsFunc(v Vertex) float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
